#pragma once
#include "Socket.h"
#include<sys/select.h>
class SelectServer
{
private:
    int listenSock_;
    int port_;
private:
    void ClearFdArray(int fd_array[],int num,int default_fd)
    {
        for(int i = 0; i < num; ++i)
            fd_array[i] = default_fd;
    }
    bool SetFdArray(int fd_array[],int num,int fd)
    {
        for(int i = 0; i < num; ++i)
        {
            if(fd_array[i] == -1)
            {
                fd_array[i] = fd;
                return true;
            }
        }
        return false;
    }
public:
    SelectServer(int port):port_(port){}
    void Init()
    {
        listenSock_ = Socket::SocketCreate();
        Socket::SocketBind(listenSock_,port_);
        Socket::SocketListen(listenSock_,5);
    }
    void Run()
    {
        fd_set readfds;//读文件描述符集
        int fd_array[128];//保存需要被监视读事件是否就绪的文件描述符
        ClearFdArray(fd_array,128,-1);
        fd_array[0] = listenSock_;
        while(true)
        {
            FD_ZERO(&readfds);//清理readfds
            int maxfd = -1;
            for(int i = 0; i < 128; ++i)
            {
                if(fd_array[i] == -1)
                    continue;
                FD_SET(fd_array[i],&readfds);
                if(fd_array[i] > maxfd)
                    maxfd = fd_array[i];
            }
            switch(select(maxfd+1,&readfds,nullptr,nullptr,nullptr))
            {
                case 0:
                    std::cout << "timeout..." << std::endl;
                    break;
                case -1:
                    std::cerr << "select error" << std::endl;
                    break;
                default:
                    HandlerEvent(readfds,fd_array,128);
                    break;
            }
        }
    }
    void HandlerEvent(const fd_set& readfds,int fd_array[],int num)
    {
        for(int i = 0; i < num; ++i)
        {
            if(fd_array[i] == -1)
                continue;
            if(fd_array[i] == listenSock_ && FD_ISSET(fd_array[i],&readfds))
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int sock = accept(listenSock_,(struct sockaddr*)&peer,&len);
                if(sock < 0)
                {
                    std::cerr << "accept error" << std::endl;
                    continue;
                }
                std::string peer_ip = std::string(inet_ntoa(peer.sin_addr));
                int peer_port = ntohs(peer.sin_port);
                std::cout << "Get a new link[" << peer_ip << ":" << peer_port << "]" << std::endl;
                
                if(!SetFdArray(fd_array,num,sock))
                {
                    close(sock);
                    std::cout << "select server is full,close sock" << std::endl;
                }
            }
            else if(FD_ISSET(fd_array[i],&readfds))
            {
                char buffer[1024];
                int size = read(fd_array[i],buffer,sizeof(buffer)-1);
                std::cout << "size : " << size << std::endl;
                if(size > 0)
                {
                    buffer[size-2] = '\0';
                    std::cout << "echo:" << buffer << std::endl;
                }
                else if(size == 0)
                {
                    std::cout << "client close" << std::endl;
                    close(fd_array[i]);
                    fd_array[i] = -1;
                }
                else
                {
                    std::cerr << "read error" << std::endl;
                    close(fd_array[i]);
                    fd_array[i] = -1;
                }
            }
        }
    }
    ~SelectServer()
    {
        if(listenSock_ >= 0)
            close(listenSock_);
    }
};